#include "server_core.h"
#include "user_manager.h"
#include "room_manager.h"
#include "utils.h"

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <sstream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <cstring>
#include <cstdlib>
#include <signal.h>

using namespace std;

vector<int> client_fds;
RoomManager room_manager;
bool server_running = true;
int global_server_fd = -1;

void handle_sigint(int signum)
{
    std::cout << "\n[Server] Caught SIGINT, shutting down..." << std::endl;

    if (global_server_fd != -1)
    {
        close(global_server_fd);
    }

    std::cout << "\033[0m" << std::flush; // 恢复终端颜色
    log_to_file("[Server] Shutdown by SIGINT.\n");
    exit(0); // 正常退出程序
}

void broadcast(int sender_fd, const string& msg)
{
    string room = room_manager.get_user_room(sender_fd);
    for (int fd : client_fds)
    {
        if (fd != sender_fd && room_manager.get_user_room(fd) == room)
        {
            send(fd, msg.c_str(), msg.size(), 0);
        }
    }
}

void run_server(int port)
{
    std::ofstream clear("chat_log.txt", std::ios::out);
    clear.close();
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("socket failed");
        exit(1);
    }
    signal(SIGINT, handle_sigint);     
    global_server_fd = server_fd;

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_fd, (const struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        perror("bind failed");
        exit(1);
    }

    if (listen(server_fd, 10) < 0)
    {
        perror("listen");
        exit(1);
    }

    fd_set all_set, read_set;
    FD_ZERO(&all_set);
    FD_SET(server_fd, &all_set);
    int max_fd = server_fd;

    cout << "Server listening on port " << port << "..." << endl;

    while (true)
    {
        read_set = all_set;
        if (select(max_fd + 1, &read_set, nullptr, nullptr, nullptr) < 0)
        {
            perror("select failed");
            break;
        }

        // 新客户端连接
        if (FD_ISSET(server_fd, &read_set))
        {
            sockaddr_in cli_addr{};
            socklen_t len = sizeof(cli_addr);
            int client_fd = accept(server_fd, (sockaddr*)&cli_addr, &len);
            if (client_fd < 0) continue;

            char name_buf[32];
            int n = recv(client_fd, name_buf, sizeof(name_buf) - 1, 0);
            if (n <= 0)
            {
                close(client_fd);
                continue;
            }
            name_buf[n] = '\0';
            string nickname = name_buf;

            if (is_nickname_taken(nickname))
            {
                string msg = color_wrap("[Server] Nickname already in use.\n", Color::RED);
                send(client_fd, msg.c_str(), msg.size(), 0);
                close(client_fd);
                continue;
            }

            add_user(client_fd, nickname);
            client_fds.push_back(client_fd);
            FD_SET(client_fd, &all_set);
            max_fd = max(max_fd, client_fd);

            string err;
            room_manager.join(client_fd, "lobby", "", err);

            string msg = color_wrap(get_current_time() + " [Server] " + nickname + " joined.\n", Color::GREEN);
            broadcast(client_fd, msg);
            cout << msg;
            log_to_file(msg);
        }

        // 客户端消息处理
        for (size_t i = 0; i < client_fds.size(); ++i)
        {
            int fd = client_fds[i];
            if (FD_ISSET(fd, &read_set))
            {
                char buf[1024];
                int n = recv(fd, buf, sizeof(buf) - 1, 0);
                if (n <= 0)
                {
                    string left = color_wrap(get_current_time() + " [Server] " + get_nickname(fd) + " left.\n", Color::YELLOW);
                    broadcast(fd, left);
                    cout << left;
                    log_to_file(left);

                    FD_CLR(fd, &all_set);
                    close(fd);
                    remove_user(fd);
                    room_manager.leave(fd);
                    client_fds.erase(client_fds.begin() + i);
                    --i;
                    continue;
                }

                buf[n] = '\0';
                string msg(buf);

                if (msg == "/quit\n")
                {
                    string left = color_wrap(get_current_time() + " [Server] " + get_nickname(fd) + " left.\n", Color::YELLOW);
                    broadcast(fd, left);
                    cout << left;
                    log_to_file(left);

                    FD_CLR(fd, &all_set);
                    close(fd);
                    remove_user(fd);
                    room_manager.leave(fd);
                    client_fds.erase(client_fds.begin() + i);
                    --i;
                    continue;
                }
                else if (msg.rfind("/who", 0) == 0)
                {
                    string list = color_wrap("[Online users]\n", Color::CYAN);
                    for (auto name : get_all_nicknames())
                    {
                        list += "- " + name + "\n";
                    }
                    send(fd, list.c_str(), list.size(), 0);
                }
                else if (msg.rfind("/to", 0) == 0)
                {
                    string content = msg.substr(4);
                    size_t space = content.find(' ');
                    if (space == string::npos)
                    {
                        string err = "[Server] Usage: /to <name> <msg>\n";
                        send(fd, err.c_str(), err.size(), 0);
                        continue;
                    }

                    string target = content.substr(0, space);
                    string real_msg = content.substr(space + 1);
                    int target_fd = get_fd_by_name(target);

                    if (target_fd == -1)
                    {
                        string err = "[Server] No such user: " + target + "\n";
                        send(fd, err.c_str(), err.size(), 0);
                    }
                    else
                    {
                        string from = get_nickname(fd);
                        string final_msg = color_wrap(get_current_time() + " [Private from " + from + "] " + real_msg, Color::CYAN);
                        send(target_fd, final_msg.c_str(), final_msg.size(), 0);
                        send(fd, final_msg.c_str(), final_msg.size(), 0);
                        log_to_file("[Private] " + from + " → " + target + ": " + real_msg);
                    }
                }
                else if (msg.rfind("/join", 0) == 0)
                {
                    std::istringstream iss(msg);
                    std::string cmd, room_name, pwd;
                    iss >> cmd >> room_name >> pwd;

                    if (room_name.empty())
                    {
                        std::string err = "[Server] Usage: /join <room_name> [password]\n";
                        send(fd, err.c_str(), err.size(), 0);
                        continue;
                    }

                    std::string err;
                    if (!room_manager.join(fd, room_name, pwd, err))
                    {
                        err = "[Server] " + err;
                        send(fd, err.c_str(), err.size(), 0);
                        continue;
                    }

                    std::string join_msg = color_wrap(get_current_time() + " [Server] " + get_nickname(fd) + " joined room: " + room_name + "\n", Color::GREEN);
                    send(fd, join_msg.c_str(), join_msg.size(), 0);
                    log_to_file("[Join] " + get_nickname(fd) + " entered room: " + room_name);
                    continue;
                }
                else if (msg == "/room\n")
                {
                    std::string room = room_manager.get_user_room(fd);
                    std::string resp = "[Server] You are in room: " + room + "\n";
                    send(fd, resp.c_str(), resp.size(), 0);
                    continue;
                }
                else
                {
                    string full_msg = color_wrap(get_current_time() + " [" + get_nickname(fd) + "] " + msg, Color::RESET);
                    broadcast(fd, full_msg);
                    cout << full_msg;
                    log_to_file(full_msg);
                }
            }
        }
    }

    close(server_fd);
    std::cout << "\033[0m" << std::flush;
}

